# -*- coding: utf-8 -*-
"""
告警推送类
整合策略管理和各种推送渠道
"""

import time
import json
from typing import List, Dict, Any, Optional
import pymysql
from pymysql.cursors import DictCursor
from common.logger import get_logger
from common.config import config
from common.utils import safe_json_dumps
from .strategies import AlarmStrategyManager
from .pushers.wechat_pusher import WeChatPusher
from .pushers.email_pusher import EmailPusher

logger = get_logger(__name__)


class AlarmPusher:
    """告警推送器"""
    
    def __init__(self):
        """初始化告警推送器"""
        self.strategy_manager = AlarmStrategyManager()
        self.wechat_pusher = WeChatPusher()
        self.email_pusher = EmailPusher()
        self.mysql_client = self._create_mysql_client()
        self.check_interval = config.get('alarm.check_interval', 60)
        self.retry_times = config.get('alarm.retry_times', 3)
        self.retry_interval = config.get('alarm.retry_interval', 10)
    
    def _create_mysql_client(self) -> pymysql.Connection:
        """
        创建MySQL客户端连接
        
        Returns:
            MySQL连接对象
        """
        mysql_config = config.get('mysql', {})
        
        try:
            connection = pymysql.connect(
                host=mysql_config.get('host', 'localhost'),
                port=mysql_config.get('port', 3306),
                user=mysql_config.get('user', 'root'),
                password=mysql_config.get('password', 'password'),
                database=mysql_config.get('database', 'log_analysis'),
                charset=mysql_config.get('charset', 'utf8mb4'),
                cursorclass=DictCursor,
                autocommit=True
            )
            
            logger.info(f"成功连接到MySQL: {mysql_config.get('host')}:{mysql_config.get('port')}")
            return connection
            
        except Exception as e:
            logger.error(f"连接MySQL失败: {e}")
            raise
    
    def check_log_for_alarms(self, log_data: Dict[str, Any]) -> List[Dict[str, Any]]:
        """
        检查日志是否触发告警
        
        Args:
            log_data: 日志数据
            
        Returns:
            告警列表
        """
        try:
            # 获取匹配的策略
            matched_strategies = self.strategy_manager.check_log_against_strategies(log_data)
            
            alarms = []
            for strategy in matched_strategies:
                alarm_data = {
                    'log_data': log_data,
                    'strategy': strategy.to_dict(),
                    'alarm_timestamp': time.time(),
                    'status': 'pending'
                }
                alarms.append(alarm_data)
            
            if alarms:
                logger.info(f"日志触发 {len(alarms)} 个告警策略")
            
            return alarms
            
        except Exception as e:
            logger.error(f"检查日志告警失败: {e}")
            return []
    
    def push_alarm(self, alarm_data: Dict[str, Any]) -> bool:
        """
        推送单个告警
        
        Args:
            alarm_data: 告警数据
            
        Returns:
            是否推送成功
        """
        try:
            strategy = alarm_data.get('strategy', {})
            actions = strategy.get('actions', [])
            
            success = True
            
            for action in actions:
                action_type = action.get('type')
                action_config = action.get('config', {})
                
                if action_type == 'wechat':
                    # 企业微信推送
                    if not self.wechat_pusher.send_alarm_message(alarm_data):
                        success = False
                        logger.error("企业微信推送失败")
                
                elif action_type == 'email':
                    # 邮件推送
                    to_emails = action_config.get('to_emails', [])
                    if to_emails:
                        if not self.email_pusher.send_alarm_email(alarm_data, to_emails):
                            success = False
                            logger.error("邮件推送失败")
                    else:
                        logger.warning("邮件推送配置中缺少收件人")
                
                else:
                    logger.warning(f"未知的推送类型: {action_type}")
            
            # 更新告警状态
            self._update_alarm_status(alarm_data, 'sent' if success else 'failed')
            
            return success
            
        except Exception as e:
            logger.error(f"推送告警失败: {e}")
            self._update_alarm_status(alarm_data, 'failed')
            return False
    
    def push_alarms(self, alarm_list: List[Dict[str, Any]]) -> Dict[str, int]:
        """
        批量推送告警
        
        Args:
            alarm_list: 告警列表
            
        Returns:
            推送结果统计
        """
        success_count = 0
        failed_count = 0
        
        for alarm_data in alarm_list:
            try:
                if self.push_alarm(alarm_data):
                    success_count += 1
                else:
                    failed_count += 1
                
                # 添加延迟避免推送过快
                time.sleep(0.5)
                
            except Exception as e:
                logger.error(f"推送告警失败: {e}")
                failed_count += 1
        
        result = {
            'success_count': success_count,
            'failed_count': failed_count,
            'total_count': len(alarm_list)
        }
        
        logger.info(f"批量推送告警完成: {result}")
        return result
    
    def _update_alarm_status(self, alarm_data: Dict[str, Any], status: str) -> None:
        """
        更新告警状态
        
        Args:
            alarm_data: 告警数据
            status: 状态
        """
        try:
            with self.mysql_client.cursor() as cursor:
                sql = """
                INSERT INTO alarm_records (
                    log_id, strategy_id, strategy_name, alarm_timestamp, 
                    status, log_data, strategy_data, created_at
                ) VALUES (
                    %s, %s, %s, %s, %s, %s, %s, NOW()
                )
                """
                
                values = (
                    alarm_data.get('log_data', {}).get('log_id'),
                    alarm_data.get('strategy', {}).get('id'),
                    alarm_data.get('strategy', {}).get('name'),
                    alarm_data.get('alarm_timestamp'),
                    status,
                    safe_json_dumps(alarm_data.get('log_data', {})),
                    safe_json_dumps(alarm_data.get('strategy', {}))
                )
                
                cursor.execute(sql, values)
                
        except Exception as e:
            logger.error(f"更新告警状态失败: {e}")
    
    def process_logs_for_alarms(self, logs: List[Dict[str, Any]]) -> Dict[str, Any]:
        """
        处理日志进行告警检查
        
        Args:
            logs: 日志列表
            
        Returns:
            处理结果统计
        """
        start_time = time.time()
        
        total_alarms = 0
        triggered_alarms = 0
        
        for log_data in logs:
            try:
                # 检查是否触发告警
                alarms = self.check_log_for_alarms(log_data)
                
                if alarms:
                    # 推送告警
                    result = self.push_alarms(alarms)
                    total_alarms += result['total_count']
                    triggered_alarms += result['success_count']
                
            except Exception as e:
                logger.error(f"处理日志告警失败: {e}")
        
        end_time = time.time()
        processing_time = end_time - start_time
        
        stats = {
            'processed_logs': len(logs),
            'total_alarms': total_alarms,
            'triggered_alarms': triggered_alarms,
            'processing_time_seconds': processing_time
        }
        
        logger.info(f"告警处理完成: {stats}")
        return stats
    
    def get_alarm_stats(self) -> Dict[str, Any]:
        """
        获取告警统计信息
        
        Returns:
            告警统计信息
        """
        try:
            with self.mysql_client.cursor() as cursor:
                # 获取总告警数
                cursor.execute("SELECT COUNT(*) as total FROM alarm_records")
                total_count = cursor.fetchone()['total']
                
                # 获取各状态统计
                cursor.execute("""
                    SELECT status, COUNT(*) as count 
                    FROM alarm_records 
                    GROUP BY status
                """)
                status_stats = {row['status']: row['count'] for row in cursor.fetchall()}
                
                # 获取策略统计
                cursor.execute("""
                    SELECT strategy_name, COUNT(*) as count 
                    FROM alarm_records 
                    WHERE strategy_name IS NOT NULL
                    GROUP BY strategy_name
                """)
                strategy_stats = {row['strategy_name']: row['count'] for row in cursor.fetchall()}
                
                return {
                    'total_alarm_records': total_count,
                    'status_statistics': status_stats,
                    'strategy_statistics': strategy_stats,
                    'strategy_manager_stats': self.strategy_manager.get_strategy_stats(),
                    'wechat_pusher_stats': self.wechat_pusher.get_config_info(),
                    'email_pusher_stats': self.email_pusher.get_config_info()
                }
                
        except Exception as e:
            logger.error(f"获取告警统计信息失败: {e}")
            return {}
    
    def get_recent_alarms(self, limit: int = 100) -> List[Dict[str, Any]]:
        """
        获取最近的告警记录
        
        Args:
            limit: 返回结果数量限制
            
        Returns:
            告警记录列表
        """
        try:
            with self.mysql_client.cursor() as cursor:
                sql = """
                SELECT * FROM alarm_records 
                ORDER BY created_at DESC 
                LIMIT %s
                """
                cursor.execute(sql, (limit,))
                return cursor.fetchall()
                
        except Exception as e:
            logger.error(f"获取最近告警记录失败: {e}")
            return []
    
    def get_alarms_by_strategy(self, strategy_name: str, limit: int = 100) -> List[Dict[str, Any]]:
        """
        根据策略名称获取告警记录
        
        Args:
            strategy_name: 策略名称
            limit: 返回结果数量限制
            
        Returns:
            告警记录列表
        """
        try:
            with self.mysql_client.cursor() as cursor:
                sql = """
                SELECT * FROM alarm_records 
                WHERE strategy_name = %s
                ORDER BY created_at DESC 
                LIMIT %s
                """
                cursor.execute(sql, (strategy_name, limit))
                return cursor.fetchall()
                
        except Exception as e:
            logger.error(f"获取策略告警记录失败: {e}")
            return []
    
    def get_alarms_by_status(self, status: str, limit: int = 100) -> List[Dict[str, Any]]:
        """
        根据状态获取告警记录
        
        Args:
            status: 告警状态
            limit: 返回结果数量限制
            
        Returns:
            告警记录列表
        """
        try:
            with self.mysql_client.cursor() as cursor:
                sql = """
                SELECT * FROM alarm_records 
                WHERE status = %s
                ORDER BY created_at DESC 
                LIMIT %s
                """
                cursor.execute(sql, (status, limit))
                return cursor.fetchall()
                
        except Exception as e:
            logger.error(f"获取状态告警记录失败: {e}")
            return []
    
    def test_push_channels(self) -> Dict[str, bool]:
        """
        测试推送渠道
        
        Returns:
            各渠道测试结果
        """
        test_results = {
            'wechat': self.wechat_pusher.test_connection(),
            'email': self.email_pusher.test_connection()
        }
        
        logger.info(f"推送渠道测试结果: {test_results}")
        return test_results
    
    def close(self):
        """关闭连接"""
        try:
            if self.mysql_client:
                self.mysql_client.close()
            if self.strategy_manager:
                self.strategy_manager.close()
            logger.info("告警推送器连接已关闭")
        except Exception as e:
            logger.error(f"关闭连接时发生错误: {e}") 